﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Threading;
using Look_Through_Windows.Helper;
using Look_Through_Windows.Logic;
using PixelFormat = System.Drawing.Imaging.PixelFormat;

namespace Look_Through_Windows
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly WindowHub winHub;

        private readonly Notifier notifier = new Notifier( );

        private readonly Config config;

        private string lastip;

        public MainWindow( )
        {
            InitializeComponent( );

            if ( File.Exists( "configuration.xml" ) )
                config = Helpers.XMLDeserialize<Config>( "configuration.xml" );
            else
            {
                config = new Config( );
                Helpers.XMLSerialize( config, "configuration.xml" );
            }

            winHub = new WindowHub( config.ListeningPort );
            winHub.OnRemoteListUpdate += UpdateRemoteWindowList;
            winHub.OnSharedListUpdate += UpdateSharedWindowList;

            DispatcherTimer timer = new DispatcherTimer( );
            timer.Interval = TimeSpan.FromMilliseconds( 10 );
            timer.Tick += timer_Tick;
            timer.Start( );

            tbIP.Text = "loading ...";
            tbIP.TextAlignment = TextAlignment.Center;
            new Thread( ( ) =>
                            {
                                Thread.CurrentThread.IsBackground = true;

                                while ( true )
                                {
                                    WebClient webClient = new WebClient( );
                                    string ip = webClient.DownloadString( "http://www.icanhazip.com/" );
                                    tbIP.Dispatcher.Invoke( ( ) => tbIP.Text = ip );


                                    //auto-save ip
                                    if ( lastip != ip )
                                        SaveConnectionData( ip );
                                    lastip = ip;

                                    Thread.Sleep( TimeSpan.FromMinutes( 5 ) );
                                }
                            } ).Start( );

            //autoconnect to stuff
            foreach ( var location in config.ConnectionDataAutoConnectLocations )
            {
                if ( File.Exists( location ) )
                {
                    foreach ( var line in File.ReadAllLines( location ) )
                    {
                        if ( String.IsNullOrWhiteSpace( line ) ) continue;

                        try
                        {
                            string host = line;
                            if ( !host.Contains( ":" ) ) host += ":" + config.ListeningPort;
                            var split = host.Split( ':' );
                            bool alrdy = false;
                            foreach ( var conn in winHub.Connections )
                            {
                                if ( ( conn.Client.Client.RemoteEndPoint as IPEndPoint ).Address.Equals( IPAddress.Parse( split[ 0 ] ) ) )
                                {
                                    alrdy = true;
                                    break;
                                }
                            }
                            if ( !alrdy )
                                winHub.ConnectTo( split[ 0 ], int.Parse( split[ 1 ] ) );
                        }
                        catch ( Exception ex )
                        {

                        }
                    }
                }
            }

            //refresh windows
            Button_Click_2( null, null );
        }

        private void SaveConnectionData( string ip )
        {
            foreach ( var location in config.ConnectionDataWriteLocations )
            {
                FileInfo info = new FileInfo( location );
                if ( !Directory.Exists( info.DirectoryName ) )
                    Directory.CreateDirectory( info.DirectoryName );

                File.WriteAllText( location, ip + ":" + config.ListeningPort );
            }
        }

        void timer_Tick( object sender, EventArgs e )
        {
            winHub.Update( );
            notifier.Update( );
        }

        void UpdateRemoteWindowList( )
        {
            lbRemoteWindows.Items.Clear( );
            foreach ( var remoteWindows in winHub.PossibleRemoteWindows )
            {
                foreach ( var remoteWindow in remoteWindows.Value.Values )
                {
                    lbRemoteWindows.Items.Add( remoteWindow );
                }
            }
        }

        private class WindowHwndWrapper
        {
            public IntPtr hwnd;
            public string name;

            public override string ToString( )
            {
                return name;
            }
        }

        private void Button_Click_2( object sender, RoutedEventArgs e )
        {
            pWindows.Children.Clear( );
            WindowExtract.EnumWindows(
                ( hwnd, lparan ) =>
                {
                    if ( WindowExtract.GetWindowTextLength( hwnd ) == 0 ) return true;
                    RECT r;
                    WindowExtract.GetWindowRect( hwnd, out r );
                    if ( r.Left >= r.Right ) return true;
                    if ( r.Top >= r.Bottom ) return true;
                    if ( !WindowExtract.IsWindow( hwnd ) ) return true;
                    if ( !WindowExtract.IsWindowVisible( hwnd ) ) return true;

                    WINDOWINFO info = new WINDOWINFO( );
                    WindowExtract.GetWindowInfo( hwnd, ref info );

                    int w = info.rcWindow.Right - info.rcWindow.Left;
                    int h = info.rcWindow.Bottom - info.rcWindow.Top;

                    {
                        StringBuilder sb = new StringBuilder( 257 );
                        WindowExtract.GetWindowText( hwnd, sb, 256 );

                        var wrapper = new WindowHwndWrapper( )
                                          {
                                              hwnd = hwnd,
                                              name = sb.ToString( )
                                          };

                        GroupBox box = new GroupBox( );
                        string header = "(" + w + "x" + h + ") " + sb.ToString( );
                        int max = 40;
                        if ( header.Length > max ) header = header.Substring( 0, max - 2 ) + "...";
                        box.Header = header;

                        int width = -1, height = -1;

                        IntPtr buffer;
                        try
                        {
                            buffer = WindowExtract.ExtractAllocate( wrapper.hwnd, ref width, ref height );
                        }
                        catch ( SEHException ex )
                        {
                            return true;
                        }

                        WriteableBitmap bmp = new WriteableBitmap( width, height, 96, 96, PixelFormats.Bgr32, null );
                        bmp.WritePixels( new Int32Rect( 0, 0, width, height ), buffer, width * height * 4, width * 4 );
                        WindowExtract.ExtractDeallocate( buffer );

                        Image img = new Image( );
                        box.Content = img;
                        img.Source = bmp;

                        box.Width = 250;
                        box.Height = 200;
                        img.Stretch = Stretch.Uniform;

                        pWindows.Children.Add( box );

                        box.MouseDoubleClick += ( o, args ) =>
                                                    {
                                                        winHub.AddSharingWindow( wrapper.hwnd );
                                                        UpdateSharedWindowList( );
                                                    };
                    }
                    return true;
                }, 0 );
        }

        private void UpdateSharedWindowList( )
        {
            lbSharedWindows.Items.Clear( );
            foreach ( var sharingWindow in winHub.SharedWindows.Values )
                lbSharedWindows.Items.Add( sharingWindow );
        }

        private void Button_Click_4( object sender, RoutedEventArgs e )
        {
            string host = tbHost.Text;
            if ( !host.Contains( ":" ) ) host += ":" + config.ListeningPort;
            var split = host.Split( ':' );
            winHub.ConnectTo( split[ 0 ], int.Parse( split[ 1 ] ) );
        }

        private void Button_Click_5( object sender, RoutedEventArgs e )
        {
            RemoteWindow win = lbRemoteWindows.SelectedItem as RemoteWindow;
            if ( win == null ) return;

            win.RequestSharing( );
        }

    }
}
